package com.ybe.util;

import java.io.File;
import java.io.IOException;
import java.net.URL;
import java.util.ArrayList;
import java.util.Enumeration;
import java.util.List;
import java.util.jar.JarEntry;
import java.util.jar.JarFile;

public class ReflectionUtil {

    public static List<String> scanAndGetAllClasses() throws IOException {
        return scanAndGetAllClasses(null);
    }

    public static List<String> scanAndGetAllClasses(String basePackage) throws IOException {
        ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
        
        // 改进的资源扫描方式
        List<String> classNames = new ArrayList<>();
        
        if (basePackage != null && !basePackage.isEmpty()) {
            // 扫描特定包
            String packagePath = basePackage.replace('.', '/');
            Enumeration<URL> resources = classLoader.getResources(packagePath);
            processResources(resources, basePackage, classNames);
        } else {
            // 扫描所有包 - 使用更可靠的方法
            scanAllPackages(classLoader, classNames);
        }
        
        return classNames;
    }

    private static void scanAllPackages(ClassLoader classLoader, List<String> classNames) throws IOException {
        // 方法1: 尝试从classpath根目录扫描
        try {
            Enumeration<URL> resources = classLoader.getResources("");
            processResources(resources, "", classNames);
        } catch (Exception e) {
            System.out.println("Failed to scan root resources: " + e.getMessage());
        }
        
        // 方法2: 如果方法1失败，尝试从已知的包开始扫描
        if (classNames.isEmpty()) {
            System.out.println("Trying alternative scanning method...");
            String[] commonPackages = {"com.ybe", "java", "javax"};
            for (String pkg : commonPackages) {
                try {
                    String packagePath = pkg.replace('.', '/');
                    Enumeration<URL> resources = classLoader.getResources(packagePath);
                    processResources(resources, pkg, classNames);
                } catch (Exception e) {
                    System.out.println("Failed to scan package " + pkg + ": " + e.getMessage());
                }
            }
        }
    }

    private static void processResources(Enumeration<URL> resources, String basePackage, List<String> classNames) throws IOException {
        while (resources.hasMoreElements()) {
            URL resource = resources.nextElement();

            if (resource.getProtocol().equals("file")) {
                processFileDirectory(new File(resource.getPath()), basePackage, classNames);
            } else if (resource.getProtocol().equals("jar")) {
                processJarFile(resource, basePackage, classNames);
            }
        }
    }

    /**
     * 递归处理文件目录
     *
     * @param directory   当前扫描的目录
     * @param packageName 当前包名
     */
    private static void processFileDirectory(File directory, String packageName, List<String> classNames) {
        File[] files = directory.listFiles();
        if (files == null) {
            return;
        }

        for (File file : files) {
            if (file.isDirectory()) {

                // 递归处理子目录，更新包名
                String newPackage = packageName.isEmpty() ?
                        file.getName() : packageName + "." + file.getName();
                processFileDirectory(file, newPackage, classNames);
            } else if (file.getName().endsWith(".class")) {
                // 处理类文件
                processClassFile(file, packageName, classNames);
            }
        }
    }

    /**
     * 处理单个类文件
     */
    private static void processClassFile(File classFile, String packageName, List<String> classNames) {
        String className = convertToClassName(classFile, packageName);
        classNames.add(className);
    }

    /**
     * 修复后的类名转换方法 - 保留包结构
     */
    private static String convertToClassName(File classFile, String packageName) {
        String fileName = classFile.getName();
        String className = fileName.substring(0, fileName.length() - 6); // 移除 .class 后缀

        // 组合完整类名（包名 + 类名）
        if (!packageName.isEmpty()) {
            return packageName + "." + className;
        }
        return className;
    }

    /**
     * 处理JAR文件
     */
    private static void processJarFile(URL jarUrl, String basePackage, List<String> classNames) throws IOException {
        String jarPath = jarUrl.getPath();

        // 改进的JAR路径解析
        if (jarPath.startsWith("file:")) {
            jarPath = jarPath.substring(5); // 移除 "file:" 前缀
        }
        
        // 移除 "!/" 后面的内容
        if (jarPath.contains("!/")) {
            jarPath = jarPath.substring(0, jarPath.indexOf("!/"));
        }
        
        // URL解码
        try {
            jarPath = java.net.URLDecoder.decode(jarPath, "UTF-8");
        } catch (Exception e) {
            System.out.println("Failed to decode jar path: " + e.getMessage());
        }
        

        // Windows路径处理
        if (jarPath.startsWith("/") && File.separatorChar == '\\') {
            jarPath = jarPath.substring(1);
        }

        try (JarFile jar = new JarFile(jarPath)) {
            Enumeration<JarEntry> entries = jar.entries();
            int count = 0;

            while (entries.hasMoreElements()) {
                JarEntry entry = entries.nextElement();
                String entryName = entry.getName();

                if (entryName.endsWith(".class")) {
                    String className = entryName
                            .replace('/', '.')
                            .substring(0, entryName.length() - 6);
                    
                    // 如果指定了基础包，只添加该包下的类
                    if (basePackage == null || basePackage.isEmpty() || 
                        className.startsWith(basePackage)) {
                        classNames.add(className);
                        count++;
                    }
                }
            }
        } catch (Exception e) {
            System.err.println("Error processing jar file " + jarPath + ": " + e.getMessage());
            e.printStackTrace();
        }
    }
}